package com.slt.developkitweb.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Lists;
import com.slt.developkitpersistent.dto.UserDto;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.*;

@Slf4j
@Component
public class EsUtil {

    public static String separator = "%26";

    @Value("${es.baseUrl:http://testh5.b2bjoy.test/qd-travel-gateway/commones}")
    private String esBaseUrl;

    private static String esUrl;

    @PostConstruct
    public void initStatic() {
        esUrl = this.esBaseUrl;
    }

    /**
     * @param indexName
     * @param queryFieldConditions 查询条件
     * @param sortFieldConditions  排序条件
     * @return java.util.List<T>
     * @MethodName queryList
     * @Description 列表查询   (建议使用 queryListV3)
     * @Author xuyunfengfb
     * @Date 2023/9/1 11:40
     **/
    public static <T> List<T> queryListV2(String indexName, String queryFieldConditions, String sortFieldConditions, Class clazz) {
        return queryPageList(indexName, queryFieldConditions, sortFieldConditions, null, null, clazz);
    }

    /**
     * @param esQueryDto 查询对象参数
     * @return java.util.List<T>
     * @MethodName queryListV3
     * @Description 列表查询  （支持模糊查 ，IN）
     * @Author xuyunfengfb
     * @Date 2023/9/5 9:42
     **/
    public static <T> List<T> queryListV3(EsQueryDto esQueryDto, String indexName, Class clazz) throws Exception {
        esQueryDto.setPageNo(1);
        esQueryDto.setPageSize(10000);
        return queryPageList(esQueryDto, indexName, clazz);
    }

    /**
     * @param esQueryDto 查询对象参数
     * @return com.cmft.b2bjoy.train.server.dto.PageData
     * @MethodName queryPage  分页对象
     * @Description 分页查询
     * @Author xuyunfengfb
     * @Date 2023/9/4 15:01
     **/
    public static <T> PageData queryPage(EsQueryDto esQueryDto, String indexName, Class clazz) throws Exception {
        StringBuffer queryUrl = new StringBuffer();
        queryUrl.append(esUrl).append("/countWrapperBody");
        esQueryDto.setIndexName(indexName);
        String post = HttpUtil.post(queryUrl.toString(), JSON.toJSONString(esQueryDto, SerializerFeature.DisableCircularReferenceDetect));
        JSONObject jsonObject = JSON.parseObject(post);
        String code = jsonObject.getString("code");
        if (!code.equals("200") || jsonObject.getJSONObject("data") == null) {
            log.error("ES执行查询总行数失败，queryUrl：{} _____  return:{}", queryUrl, post);
            throw new Exception("ES执行查询总行数失败， return:" + post);
        }
        int totalSize = (int) (jsonObject.getJSONObject("data").get("total"));
        List<T> ts = queryPageList(esQueryDto, indexName, clazz);
        return new PageData(totalSize, esQueryDto.getPageNo(), esQueryDto.getPageSize(), ts);
    }

    /**
     * @param indexName 索引名
     * @param clazz     数据对象
     * @MethodName insertEsById
     * @Description 单条更新
     * @Author xuyunfengfb
     * @Date 2023/8/10 17:58
     **/
    public static <T> Boolean insertEsById(String indexName, T clazz) {
        Boolean zt = false;
        for (int i = 0; i < 3; i++) {
            boolean insert = EsUtil.insert(indexName, JSONObject.toJSONString(clazz));
            if (insert) {
                zt = true;
                break;
            }
        }
        return zt;
    }

    /**
     * @param indexName
     * @param queryFieldConditions
     * @return java.lang.String
     * @MethodName query
     * @Description 查询ES列表 ( 建议使用 queryListV3)
     * @Author xuyunfengfb
     * @Date 2023/8/3 17:29
     **/
    public static <T> List<T> queryList(String indexName, String queryFieldConditions, Class<T> clazz) {
        StringBuffer queryUrl = new StringBuffer();
        queryUrl.append(esUrl).append("/query")
                .append("?indexName=" + indexName + "&queryFieldConditions=")
                .append(queryFieldConditions);
        String post = HttpUtil.post(queryUrl.toString(), new HashMap<String, Object>());
        JSONObject jsonObject = JSON.parseObject(post);
        String code = jsonObject.getString("code");
        ArrayList<T> ts = new ArrayList<>();
        if (!code.equals("200")) {
            log.error("ES执行查询失败，queryUrl：{} _____  return:{}", queryUrl, post);
            return ts;
        }
        JSONObject data = jsonObject.getJSONObject("data");
        return JSONObject.parseArray(data.get("list").toString(), clazz);
    }



    //////////////////////////////////       私有方法    /////////////////////////////////////////////////////////////////////////////////

    /**
     * @param indexName
     * @param jsonString
     * @MethodName insert
     * @Description ES单条插入
     * @Author xuyunfengfb
     * @Date 2023/8/3 17:30
     **/
    private static boolean insert(String indexName, String jsonString) {
        StringBuffer insertUrl = new StringBuffer();
        insertUrl.append(esUrl).append("/insert")
                .append("?indexName=" + indexName + "&")
                .append("primaryKeyPolicy=1&refreshPolicy=2&");

        insertUrl.append("data=" + jsonString);
        String post = HttpUtil.post(insertUrl.toString(), new HashMap<String, Object>());
        JSONObject jsonObject = JSONObject.parseObject(post);
        String code = jsonObject.getString("code");
        if (!code.equals("200")) {
            log.error("ES单条更新失败，queryUrl：{} _____  return:{}", insertUrl.toString(), post);
            return false;
        }
        return true;
    }

    /**
     * @param indexName
     * @param queryFieldConditions
     * @return java.lang.String
     * @MethodName query
     * @Description 查询ES列表
     * @Author xuyunfe
     * @Date 2023/8/3 17:29
     **/
    private static <T> List<T> queryPageList(String indexName, String queryFieldConditions, String sortFieldConditions, Integer pageNum, Integer pageSize, Class<T> clazz) {
        StringBuffer queryUrl = new StringBuffer();
        queryUrl.append(esUrl).append("/query")
                .append("?indexName=" + indexName);
        if (StrUtil.isNotBlank(queryFieldConditions))
            queryUrl.append("&" + queryFieldConditions);
        if (pageNum != null)
            queryUrl.append("&pageNum=" + pageNum);
        if (pageSize != null)
            queryUrl.append("&pageSize=" + pageSize);
        if (StrUtil.isNotBlank(sortFieldConditions))
            queryUrl.append("&" + sortFieldConditions);
        String post = HttpUtil.post(queryUrl.toString(), new HashMap<String, Object>());
        JSONObject jsonObject = JSON.parseObject(post);
        String code = jsonObject.getString("code");
        ArrayList<T> ts = new ArrayList<>();
        if (!code.equals("200")) {
            log.error("ES执行查询失败，queryUrl：{} _____  return:{}", queryUrl, post);
            return ts;
        }
        return JSONObject.parseArray(jsonObject.getJSONObject("data").get("list").toString(), clazz);
    }

    /**
     * @param esQueryDto
     * @return java.util.List<T>
     * @MethodName queryPageList
     * @Description 分页查询
     * @Author xuyunfengfb
     * @Date 2023/9/12 15:05
     **/
    private static <T> List<T> queryPageList(EsQueryDto esQueryDto, String indexName, Class clazz) throws Exception {
        StringBuffer queryUrl = new StringBuffer();
        queryUrl.append(esUrl).append("/queryWrapperBody");
        esQueryDto.setIndexName(indexName);
        String s = JSON.toJSONString(esQueryDto, SerializerFeature.DisableCircularReferenceDetect);
        String post = HttpUtil.post(queryUrl.toString(), s);
        JSONObject jsonObject = JSON.parseObject(post);
        String code = jsonObject.getString("code");
        ArrayList<T> ts = new ArrayList<>();
        if (!code.equals("200")) {
            log.error("ES执行查询失败，queryUrl：{} ______Dto:{} ______  return:{}", queryUrl, s, post);
            throw new Exception("es查询失败");
        }
        return JSONObject.parseArray(jsonObject.getJSONObject("data").get("list").toString(), clazz);
    }



    /**
     * @param indexName
     * @param clazz
     * @MethodName ES创建索引
     * @Description
     * @Author xuyunfengfb
     * @Date 2023/8/3 16:08
     **/
    private static void createIndex(String indexName, Class clazz) {
        StringBuffer createUrl = new StringBuffer();
        createUrl.append(esUrl).append("/index/create").append("?indexName=" + indexName + "&");
        Map<String, Object> paramMap = convert(clazz);
        for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
            createUrl.append("fieldNameTypeList=" + entry.getKey() + separator + entry.getValue() + "&");
        }
        String post = HttpUtil.post(createUrl.toString(), new HashMap<String, Object>());
        log.info(post);
    }

    /**
     * @param clazz
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @MethodName convert
     * @Description 对象转换
     * @Author xuyunfengfb
     * @Date 2023/9/12 15:06
     **/
    static private Map<String, Object> convert(Class clazz) {
        Map map = new HashMap<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            map.put(field.getName(), field.getType().getName());
        }
        return map;
    }

    public static EsQueryDto getEqualQueryCondition(Object object){
        EsQueryDto esQueryDto = new EsQueryDto();
        List<EsQueryDto.QueryCondition> queryConditionList = new ArrayList<>();
        //添加查询条件
        try {
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if(!Objects.isNull(field.get(object))){
                    EsQueryDto.QueryCondition queryCondition = new EsQueryDto.QueryCondition();
                    queryCondition.setFieldName(field.getName());
                    queryCondition.setCondition("=");
                    queryCondition.setValues(Lists.newArrayList(field.get(object)));
                    queryConditionList.add(queryCondition);
                }
            }
            esQueryDto.setQueryFieldConditions(queryConditionList);
        }catch (Exception e){
            log.info(e.getMessage());
        }

        return esQueryDto;
    }
    @Data
    static class EsBatchEntity {
        private String indexName;
        private String jsonArrayStr;//需要插入的数据集合
        private String primaryKeyPolicy;//0 自动生成 ,1 数据源指定主键
        private String refreshPolicy;//0 不刷新1 等待刷新2 立即刷新
    }

    @Data
    public static class EsQueryDto {

        private String indexName;

        /**
         * 查询条件
         */
        private List<QueryCondition> queryFieldConditions;

        /**
         * 删除条件
         */
        private List<QueryCondition> deleteFieldConditions;

        /**
         * 排序
         */
        private List<SortCondition> sortFieldConditions;

        /**
         * 当前页码
         * <p>
         * 未指定默认1
         */
        private Integer pageNo = 1;

        /**
         * 单次查询数量
         * <p>
         * 未指定默认1000
         */
        private Integer pageSize = 10;

        /**
         * 滚动查询id
         */
        private String scrollId;

        @Data
        public static class QueryCondition {

            /**
             * 字段名
             */
            private String fieldName;

            /**
             * 查询条件
             */
            private String condition;

            /**
             * 查询条件对应的值
             */
            private List values;
        }

        @Data
        public class SortCondition {

            /**
             * 字段名
             */
            private String fieldName;

            /**
             * 排序类型
             */
            private String sortType;

        }

    }

    @Data
    public static class PageData<T> {
        /**
         * 总记录数
         */
        public int totalSize;
        /**
         * 总页数
         */
        public int totalPageCount;
        /**
         * 当前页数
         */
        public int pageNum;
        /**
         * 每页展示行数
         */
        public int pageSize;
        /**
         * 列表数据
         */
        public List<T> rows;

        public PageData() {
        }

        public PageData(int totalSize, int pageNum, int pageSize, List<T> rows) {
            this.totalSize = totalSize;
            this.pageNum = pageNum;
            this.pageSize = pageSize;
            this.rows = rows;
            this.totalPageCount = (int) Math.ceil((double) this.totalSize / this.pageSize);
        }
    }


    public static void main(String[] args) {
        UserDto userDto = new UserDto();
        userDto.setCode("22");
        EsUtil.EsQueryDto equalQueryCondition = EsUtil.getEqualQueryCondition(userDto);
        System.out.println(equalQueryCondition);
    }
}